/**
 * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd
 * author: hertz.wang hertz.wong@rock-chips.com
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include "camera_mp4.h"

CameraMp4::CameraMp4() {
#ifdef DEBUG
  snprintf(class_name, sizeof(class_name), "CameraMp4");
#endif
  snprintf(format, sizeof(format), "mp4");
  direct_piece = true;
  exit_id = MUXER_NORMAL_EXIT;
  no_async = true;  // no cache packet list and no thread handle
  memset(&lbr_pre_timeval, 0, sizeof(struct timeval));
  low_frame_rate_mode = false;
}

CameraMp4::~CameraMp4() {}

bool CameraMp4::is_low_frame_rate() {
  return low_frame_rate_mode != MODE_NORMAL;
}

void CameraMp4::set_low_frame_rate(uint32_t val, struct timeval start_timeval) {
  low_frame_rate_mode = val;
  printf("set mp4 low bit rate: 0x%x\n", low_frame_rate_mode);
  if (val != MODE_NORMAL)
    lbr_pre_timeval = start_timeval;
  else
    memset(&lbr_pre_timeval, 0, sizeof(struct timeval));
}

void CameraMp4::reset_lbr_time() {
  if (is_low_frame_rate())
    memset(&lbr_pre_timeval, 0, sizeof(struct timeval));
}

static void add_one_frame_time(struct timeval& val, int video_sample_rate) {
  int64_t usec = (int64_t)val.tv_usec + 1000000LL / video_sample_rate;
  val.tv_sec += (usec / 1000000LL);
  val.tv_usec = (usec % 1000000LL);
}

void CameraMp4::push_packet(EncodedPacket* pkt) {
  // av_log(NULL, AV_LOG_ERROR, "CameraMp4::push_packet, low_frame_rate_mode:
  // %d\n", low_frame_rate_mode);
  if (is_low_frame_rate()) {
    if (pkt->type == AUDIO_PACKET)
      return;
    // only save the key frame and readjust timestamp
    AVPacket& avpkt = pkt->av_pkt;
    if ((low_frame_rate_mode & MODE_ONLY_KEY_FRAME) &&
        !(avpkt.flags & AV_PKT_FLAG_KEY)) {
      av_log(NULL, AV_LOG_ERROR, " non key frame\n");
      if (lbr_pre_timeval.tv_sec == 0 && lbr_pre_timeval.tv_usec == 0) {
        pkt->lbr_time_val = pkt->time_val;
      } else {
        pkt->lbr_time_val = lbr_pre_timeval;
      }
      return;
    }

    struct timeval tval = pkt->time_val;
    if ((lbr_pre_timeval.tv_sec == 0 && lbr_pre_timeval.tv_usec == 0) ||
        (((tval.tv_sec - lbr_pre_timeval.tv_sec) * 1000000LL +
          (tval.tv_usec - lbr_pre_timeval.tv_usec)) /
             1000 * video_sample_rate <
         1000)) {
      PRINTF_FUNC_LINE;
      lbr_pre_timeval = tval;
    }
    add_one_frame_time(lbr_pre_timeval, video_sample_rate);
    pkt->lbr_time_val = lbr_pre_timeval;
  }
  CameraMuxer::push_packet(pkt);
}
